<template>
  <div class="pacman-game">
    <div v-for="(row, rowIndex) in gameMap" :key="rowIndex" class="game-row">
      <div
          v-for="(cell, colIndex) in row"
          :key="colIndex"
          class="game-cell"
          :class="{
          'pacman': cell === 1,
          'dot': cell === 2,
          'empty': cell === 0
        }"
      ></div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';

const ROWS = 8;
const COLS = 60;
// 初始化吃豆人位置
const pacmanX = ref(0);
const pacmanY = ref(0);
// 初始化游戏地图
const gameMap = ref<number[][]>([]);
// 定义路径
const path: { x: number; y: number }[] = [];
// 路径索引
let pathIndex = 0;
// 定时器 ID
let intervalId: number | null = null;

// 随机生成豆子位置
const generateDots = () => {
  gameMap.value = Array.from({ length: ROWS }, () => Array(COLS).fill(0));
  const dotCount = Math.floor(ROWS * COLS * 0.4); // 豆子数量占地图的 40%
  const availablePositions: [number, number][] = [];
  for (let y = 0; y < ROWS; y++) {
    for (let x = 0; x < COLS; x++) {
      availablePositions.push([y, x]);
    }
  }
  // 打乱位置数组
  for (let i = availablePositions.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [availablePositions[i], availablePositions[j]] = [availablePositions[j], availablePositions[i]];
  }
  // 放置豆子
  for (let i = 0; i < dotCount; i++) {
    const [y, x] = availablePositions[i];
    gameMap.value[y][x] = 2;
  }
  // 初始化吃豆人位置
  pacmanX.value = 0;
  pacmanY.value = 0;
  gameMap.value[pacmanY.value][pacmanX.value] = 1;
  path.length = 0;
  pathIndex = 0;
};

// 广度优先搜索寻找最短路径
const bfs = (startX: number, startY: number): { x: number; y: number }[] | null => {
  const queue: { x: number; y: number; path: { x: number; y: number }[] }[] = [
    { x: startX, y: startY, path: [] }
  ];
  const visited = new Set<string>();
  visited.add(`${startX},${startY}`);

  while (queue.length > 0) {
    const { x, y, path } = queue.shift()!;

    if (gameMap.value[y][x] === 2) {
      return path;
    }

    const directions = [
      { dx: -1, dy: 0 }, // 左
      { dx: 1, dy: 0 },  // 右
      { dx: 0, dy: -1 }, // 上
      { dx: 0, dy: 1 }   // 下
    ];

    for (const { dx, dy } of directions) {
      const newX = x + dx;
      const newY = y + dy;

      if (
        newX >= 0 &&
        newX < COLS &&
        newY >= 0 &&
        newY < ROWS &&
        !visited.has(`${newX},${newY}`)
      ) {
        visited.add(`${newX},${newY}`);
        queue.push({
          x: newX,
          y: newY,
          path: [...path, { x: newX, y: newY }]
        });
      }
    }
  }

  return null;
};

// 吃豆人移动逻辑
const movePacman = () => {
  if (pathIndex >= path.length) {
    const newPath = bfs(pacmanX.value, pacmanY.value);
    if (newPath) {
      path.length = 0;
      path.push(...newPath);
      pathIndex = 0;
    } else {
      // 没有豆子了，重新生成
      generateDots();
      return;
    }
  }

  const nextPos = path[pathIndex];
  const newX = nextPos.x;
  const newY = nextPos.y;

  if (newX >= 0 && newX < COLS && newY >= 0 && newY < ROWS) {
    if (gameMap.value[newY][newX] === 2) {
      // 吃到豆子
      gameMap.value[pacmanY.value][pacmanX.value] = 0;
      gameMap.value[newY][newX] = 1;
      pacmanX.value = newX;
      pacmanY.value = newY;
    } else if (gameMap.value[newY][newX] === 0) {
      // 移动到空白处
      gameMap.value[pacmanY.value][pacmanX.value] = 0;
      gameMap.value[newY][newX] = 1;
      pacmanX.value = newX;
      pacmanY.value = newY;
    }
    pathIndex++;
  }
};

onMounted(() => {
  generateDots();
  intervalId = window.setInterval(movePacman, 300);
});

onUnmounted(() => {
  if (intervalId) {
    window.clearInterval(intervalId);
  }
});
</script>

<style scoped>
.pacman-game {
  display: flex;
  flex-direction: column;
}

.game-row {
  display: flex;
  gap: 2px;
  margin-bottom: 2px;
}

.game-cell {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  background-color: white;

  .dark & {
    background-color: rgba(30, 30, 30, 0.9);
  }
}

.pacman {
  background-color: #FFC0CB;
  border-radius: 50%;

  .dark & {
    background-color: #FFC0CB;
  }
}

.dot {
  background-color: #90EE90;
  border-radius: 2px;
  width: 10px;
  height: 10px;

  .dark & {
    background-color: #99ec99;
  }
}

.empty {
  background-color: white;

  .dark & {
    background-color: rgba(51, 51, 51, 0.5);
  }
}

</style>
